using System;
using dnAnalytics.Math;
using NUnit.Framework;

namespace dnAnalytics.Tests.Math
{
    [TestFixture]
    public class ComplexTest
    {
        [Test]
        public void AbsoluteTest()
        {
            Complex a = new Complex(4, -2);
            Assert.AreEqual(4.4721359549995796, a.Absolute);
        }

        [Test]
        public void AddTest()
        {
            Complex a = new Complex(3, -3);
            Complex b = new Complex(-1, 1);
            Assert.AreEqual(new Complex(2, -2), a.Add(b));
        }

        [Test]
        public void ConjugateTest()
        {
            Complex a = new Complex(4, -2);
            Assert.AreEqual(new Complex(4, 2), a.Conjugate);
        }

        [Test]
        public void DivideTest()
        {
            Complex a = new Complex(4, -4);
            Complex b = new Complex(-2, 2);
            Assert.AreEqual(new Complex(-2, 0), a.Divide(b));
        }

        [Test]
        public void EqualsTest()
        {
            Complex cd1 = new Complex(-1.1, 2.2);
            Complex cd2 = new Complex(-1.1, 2.2);
            Assert.IsTrue(cd1 == cd2);
            Assert.IsTrue(cd1.Equals(cd2));
        }

        [Test]
        [ExpectedException(typeof (FormatException))]
        public void FormatExceptionTest1()
        {
            new Complex("");
        }

        [Test]
        [ExpectedException(typeof (FormatException))]
        public void FormatExceptionTest2()
        {
            new Complex("+");
        }

        [Test]
        [ExpectedException(typeof (FormatException))]
        public void FormatExceptionTest3()
        {
            new Complex("1i+2");
        }

        [Test]
        public void GetInfinityTest()
        {
            Assert.AreEqual(new Complex(float.PositiveInfinity, float.PositiveInfinity), Complex.Infinity);
        }

        [Test]
        public void GetNaNTest()
        {
            Assert.AreEqual(double.NaN, Complex.NaN.Real);
            Assert.AreEqual(double.NaN, Complex.NaN.Imaginary);
        }

        [Test]
        public void GetOneTest()
        {
            Assert.AreEqual(new Complex(1), Complex.One);
        }

        [Test]
        public void GetZeroTest()
        {
            Assert.AreEqual(new Complex(0, 0), Complex.Zero);
        }

        [Test]
        public void HashTest()
        {
            Complex z = new Complex(1.1, 2.2);
            Assert.AreEqual(z.GetHashCode(), 11);
        }

        [Test]
        public void InequalityTest()
        {
            Complex a = 1;
            Complex b = 2;
            Assert.IsTrue(a != b);
        }

        [Test]
        public void InfinityTest()
        {
            Complex z = new Complex(Double.NegativeInfinity, 1.1);
            Assert.IsTrue(Complex.IsInfinity(z));
            z = new Complex(1.1, Double.NegativeInfinity);
            Assert.IsTrue(Complex.IsInfinity(z));
            z = new Complex(Double.PositiveInfinity, 1.1);
            Assert.IsTrue(Complex.IsInfinity(z));
            z = new Complex(1.1, Double.PositiveInfinity);
            Assert.IsTrue(Complex.IsInfinity(z));
            z = new Complex(1.1, 2.2);
            Assert.IsFalse(Complex.IsInfinity(z));
        }

        [Test]
        public void MultiplyTest()
        {
            Complex a = new Complex(4, -4);
            Complex b = new Complex(-2, 2);
            Assert.AreEqual(new Complex(0, 16), a.Multiply(b));
        }

        [Test]
        public void NaNTest()
        {
            Complex z = new Complex(Double.NaN, 1.1);
            Assert.IsTrue(Complex.IsNaN(z));
            z = new Complex(1.1, Double.NaN);
            Assert.IsTrue(Complex.IsNaN(z));
            z = new Complex(1.1, 2.2);
            Assert.IsFalse(Complex.IsNaN(z));
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void NullString()
        {
            new Complex(null);
        }

        [Test]
        public void ParseTest()
        {
            Complex z = new Complex("1");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 0);

            z = new Complex("i");
            Assert.AreEqual(z.Real, 0);
            Assert.AreEqual(z.Imaginary, 1);

            z = new Complex("2i");
            Assert.AreEqual(z.Real, 0);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("1 + 2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("1+2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("1 - 2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("1-2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("1+-2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("1 - 2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("1,2");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("1 , 2 ");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("1,2i");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("-1, -2i");
            Assert.AreEqual(z.Real, -1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("(+1,2i)");
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);

            z = new Complex("(-1 , -2)");
            Assert.AreEqual(z.Real, -1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("(-1 , -2i)");
            Assert.AreEqual(z.Real, -1);
            Assert.AreEqual(z.Imaginary, -2);

            z = new Complex("(+1e1 , -2e-2i)");
            Assert.AreEqual(z.Real, 10);
            Assert.AreEqual(z.Imaginary, -.02);

            z = new Complex("(-1e1 + -2e2i)");
            Assert.AreEqual(z.Real, -10);
            Assert.AreEqual(z.Imaginary, -200);

            const string s = "1 + 2i";
            z = Complex.Parse(s);
            Assert.AreEqual(z.Real, 1);
            Assert.AreEqual(z.Imaginary, 2);
        }

        [Test]
        public void PlusTest()
        {
            Complex a = new Complex(1, 1);
            Assert.AreEqual(new Complex(1, 1), Complex.Plus(a));
        }

        [Test]
        public void SubtractTest()
        {
            Complex a = new Complex(3, -3);
            Complex b = new Complex(-1, 1);
            Assert.AreEqual(new Complex(4, -4), a.Subtract(b));
        }

        [Test]
        public void ToComplex()
        {
            Complex32 a = new Complex32(1, -2);
            Assert.AreEqual(new Complex(1, -2), Complex.ToComplex(a));
            Assert.AreEqual(new Complex(1), Complex.ToComplex(1.0));
        }

        [Test]
        public void ToStringTest()
        {
            Complex a = new Complex(1, -2);
            Assert.AreEqual("1 -2i", a.ToString());
        }

        [Test]
        public void TryParseFormatExceptionTest1()
        {
            Complex z;
            bool ret = Complex.TryParse("", out z);
            Assert.IsFalse(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(0, z.Imaginary);
        }

        [Test]
        public void TryParseFormatExceptionTest2()
        {
            Complex z;
            bool ret = Complex.TryParse("+", out z);
            Assert.IsFalse(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(0, z.Imaginary);
        }

        [Test]
        public void TryParseFormatExceptionTest3()
        {
            Complex z;
            bool ret = Complex.TryParse("1i+2", out z);
            Assert.IsFalse(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(0, z.Imaginary);
        }

        [Test]
        public void TryParseNullString()
        {
            Complex z;
            bool ret = Complex.TryParse(null, out z);
            Assert.IsFalse(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(0, z.Imaginary);
        }

        [Test]
        public void TryParseTest()
        {
            Complex z;
            bool ret = Complex.TryParse("1", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(0, z.Imaginary);

            ret = Complex.TryParse("i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(1, z.Imaginary);

            ret = Complex.TryParse("2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(0, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("1 + 2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("1+2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("1 - 2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("1-2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("1+-2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("1 - 2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("1,2", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("1 , 2 ", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("1,2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("-1, -2i", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(-1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("(+1,2i)", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(1, z.Real);
            Assert.AreEqual(2, z.Imaginary);

            ret = Complex.TryParse("(-1 , -2)", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(-1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("(-1 , -2i)", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(-1, z.Real);
            Assert.AreEqual(-2, z.Imaginary);

            ret = Complex.TryParse("(+1e1 , -2e-2i)", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(10, z.Real);
            Assert.AreEqual(-.02, z.Imaginary);

            ret = Complex.TryParse("(-1e1 + -2e2i)", out z);
            Assert.IsTrue(ret);
            Assert.AreEqual(-10, z.Real);
            Assert.AreEqual(-200, z.Imaginary);
        }

        [Test]
        public void UnaryPlusTest()
        {
            Complex a = new Complex(1, 1);
            Assert.AreEqual(new Complex(1, 1), +a);
        }
    }
}